package com.spbsu.search.stemmer.impl;

import com.spbsu.search.stemmer.Stemmer;

public class MyPorterStemmer implements Stemmer {
    private static final char[] vowels = {'а', 'е', 'и', 'о', 'у', 'ы', 'э', 'ю', 'я'};
    private static final CharSequence[] perfectiveG1 = {"в", "вши", "вшись"};
    private static final CharSequence[] perfectiveG2 = {"ив", "ивши", "ившись", "ыв", "ывши", "ывшись"};
    private static final CharSequence[] adjective = {"ее", "ие", "ые", "ое", "ими", "ыми", "ей", "ий", "ый", "ой", "ем", "им", "ым", "ом", "его", "ого", "ему", "ому", "их", "ых", "ую", "юю", "ая", "яя", "ою", "ею"};
    private static final CharSequence[] participleG1 = {"ем", "нн", "вш", "ющ", "щ"};
    private static final CharSequence[] participleG2 = {"ивш", "ывш", "ующ"};
    private static final CharSequence[] reflexive = {"ся", "сь"};
    private static final CharSequence[] verbG1 = {"ла", "на", "ете", "йте", "ли", "й", "л", "ем", "н", "ло", "но", "ет", "ют", "ны", "ть", "ешь", "нно"};
    private static final CharSequence[] verbG2 = {"ила", "ыла", "ена", "ейте", "уйте", "ите", "или", "ыли", "ей", "уй", "ил", "ыл", "им", "ым", "ен", "ило", "ыло", "ено", "ят", "ует", "уют", "ит", "ыт", "ены", "ить", "ыть", "ишь", "ую", "ю"};
    private static final CharSequence[] noun = {"а", "ев", "ов", "ие", "ье", "е", "иями", "ями", "ами", "еи", "ии", "и", "ией", "ей", "ой", "ий", "й", "иям", "ям", "ием", "ем", "ам", "ом", "о", "у", "ах", "иях", "ях", "ы", "ь", "ию", "ью", "ю", "ия", "ья", "я"};
    private static final CharSequence[] superlative = {"ейш", "ейше"};
    private static final CharSequence[] derivational = {"ост", "ость"};
    
    public CharSequence stem(CharSequence word) {
        //toLowerCase
        int n = word.length();
        for (int i = 0; i < n; i++ ){
            if (word.charAt(i) == 'ё'){
                word = word.subSequence(0,i) + "е" + word.subSequence(i+1,n);
            }
        }
        int suffix = n - 1;
        int fv = firstVovel(word,0,suffix) + 1;
        if (fv > suffix) {
            return word;
        } else {
            int prefix = fv;
            fv = searchForG1(word,perfectiveG1,prefix,suffix);
            if (fv == 0)
                fv = searchForG2(word, perfectiveG2,prefix,suffix);
            if (fv == 0) {
                fv = searchForG2(word, reflexive,prefix,suffix);
                if (fv > 0) {
                    suffix = suffix - fv;
                }
                fv = searchForG2(word, adjective,prefix,suffix);
                if (fv > 0) {
                    suffix = suffix - fv;
                    fv = searchForG1(word, participleG1,prefix,suffix);
                    if (fv == 0)
                        fv = searchForG2(word, participleG2,prefix,suffix);
                    if (fv > 0) {
                        suffix = suffix - fv;
                    }
                } else {
                    fv = searchForG1(word, verbG1,prefix,suffix);
                    if (fv == 0)
                        fv = searchForG2(word, verbG2,prefix,suffix);
                    if (fv > 0) {
                        suffix = suffix - fv;
                    } else {
                        fv = searchForG2(word, noun,prefix,suffix);
                        if (fv > 0) {
                            suffix = suffix - fv;
                        }
                    }
                }
            } else {
                suffix = suffix - fv;
            }
            if (search(word, "и", prefix, suffix))
                suffix = suffix - 1;
            fv = firstNonVovel(word, prefix, suffix) + 1;
            if (fv <= suffix) {
                int prefixR2 = fv;
                fv = firstVovel(word, prefixR2, suffix) + 1;
                if (fv <= suffix) {
                    prefixR2 = fv;
                    fv = firstNonVovel(word, prefixR2, suffix) + 1;
                    if (fv <= suffix) {
                        prefixR2 = fv;
                        fv = searchForG2(word, derivational, prefixR2, suffix);
                        if (fv > 0)
                            suffix = suffix - fv;
                    }
                }
            }
            if (search(word, "нн", prefix, suffix)) {
                suffix = suffix - 1;
            } else {
                fv = searchForG2(word, superlative, prefix,suffix);
                if (fv > 0) {
                    suffix = suffix - fv;
                    if (search(word, "нн", prefix,  suffix))
                        suffix = suffix - 1;
                } else {
                    if (search(word, "ь", prefix, suffix))
                        suffix = suffix -1;
                }
            }
            return word.subSequence(0,suffix + 1) ;
        }
    }
    private int firstVovel(CharSequence word, int prefix, int suffix) {
        char a;
        for (int i = prefix; i <= suffix; i++) {
            a = word.charAt(i);
            for (int j = 0; j < 9; j++) {
                if (a == vowels[j]) {
                    return i;
                }
            }
        }
        return word.length();
    }
    private int firstNonVovel(CharSequence word, int prefix, int suffix) {
        boolean f;
        char a;
        for (int i = prefix; i <= suffix; i++) {
            a = word.charAt(i);
            f = false;
            for (int j = 0; j < 9; j++) {
                if (a == vowels[j]) {
                    f = true;
                    break;
                }
            }
            if (!f) {
                return i;
            }
        }
        return suffix + 1;
    }
    private boolean search(CharSequence haystack, CharSequence needle, int prefix ,int suffix) {
        int t = needle.length();
        int h = suffix - prefix + 1;
        if (t > h){
            return false;
        }
        else{
            for (int i = 0; i < t; i++){
                if (haystack.charAt(suffix - i) != needle.charAt(t - i - 1))
                    return false;
            }
        }
        return true;
    }
    private int searchForG1(CharSequence word, CharSequence[] ending, int prefix, int suffix) {
        for (int i = 0; i < ending.length; i++) {
            if (search(word, "я" + ending[i], prefix, suffix) | search(word, "а" + ending[i], prefix, suffix))
                return ending[i].length();
        }
        return 0;
    }
    private int searchForG2(CharSequence word, CharSequence[] ending, int prefix, int suffix) {
        for (int i = 0; i < ending.length; i++) {
            if (search(word, ending[i], prefix, suffix))
                return ending[i].length();
        }
        return 0;
    } 
}
